package com.me.myFramework.myAop.aop111;

import com.me.myFramework.myAop.IBuy;
import com.me.myFramework.myAop.Switch;
import com.me.myFramework.myAop.aop111.advice.method.AfterReturningAdvice;
import com.me.myFramework.myAop.aop111.advice.method.MethodBeforeAdvice;
import com.me.myFramework.myAop.aop111.intercept.method.AfterReturningAdviceInterceptor;
import com.me.myFramework.myAop.aop111.intercept.method.MethodBeforeAdviceInterceptor;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

/**
 * 自己实现 AOP-111：  <p></p>
 *
 * 从模板方法中进一步提取增强接口：MethodBeforeAdvice、AfterReturningAdvice
 *
 * @author ME
 */
public class MyAop111 {

    /**
     * 通过 模板模式 提取增强逻辑：方法执行前、正常返回、异常返回
     */
    public static void main(String[] args) throws Throwable {
        IBuy target = new Switch();

        IBuy proxy = (IBuy) new MyAop111().getProxy(target, new MethodBeforeAdvice() {
            @Override
            public void before(Method method, Object[] args, Object target) throws Throwable {
                System.out.println("[AOP] 就想看看谁买东西了：" + args[0]);
            }
        });
        proxy.buy("Jack");

        System.out.println("\n----------------------------------------------");
        proxy = (IBuy) new MyAop111().getProxy2(target, new AfterReturningAdvice() {
            @Override
            public void afterReturning(Object returnValue, Method method, Object[] args, Object target) throws Throwable {
                System.out.println("[AOP2] 记录买了啥 " + returnValue);
            }
        });
        proxy.buy("Tom");
    }

    private Object getProxy(Object target, MethodBeforeAdvice advice) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (isCustomMethod(method.getName())) {
                    MethodBeforeAdviceInterceptor interceptor = new MethodBeforeAdviceInterceptor(advice);
                    return interceptor.invoke(method, args, target);
                }

                return method.invoke(target, args);
            }
        });
    }

    private Object getProxy2(Object target, AfterReturningAdvice advice) {
        return Proxy.newProxyInstance(Thread.currentThread().getContextClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() {
            @Override
            public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
                if (isCustomMethod(method.getName())) {
                    AfterReturningAdviceInterceptor interceptor = new AfterReturningAdviceInterceptor(advice);
                    return interceptor.invoke(method, args, target);
                }

                return method.invoke(target, args);
            }
        });
    }

    boolean isCustomMethod(String methodName) {
        return !"toString".equals(methodName) && !"hashCode".equals(methodName) && !"equals".equals(methodName)
                && !"clone".equals(methodName);
    }

}
